package main

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/qiniu/reqid.v1"
	"io"
	"os"
	"os/exec"
	_log "qiniupkg.com/x/log.v7"
	"strings"
	"time"
)

type run struct {
	timeout int
	cmd     string
}

var log = _log.New(os.Stderr, "[CI_TESTER-"+reqid.Gen()+"]", _log.Ldefault)

func (r *run) exec() {
	cmd := exec.Command("bash", "-c", r.cmd)
	log.Infof(cyan("task %q start"), r.cmd)
	start := time.Now()

	var combinedOutput bytes.Buffer
	var stdout, stderr bytes.Buffer
	cmd.Stdout = io.MultiWriter(&combinedOutput, &stdout)
	cmd.Stderr = io.MultiWriter(&combinedOutput, &stderr)

	err := cmd.Start()
	if err != nil {
		log.Fatal(err)
	}
	done := make(chan error)
	go func() { done <- cmd.Wait() }()
	select {
	case err = <-done:
		useTime := time.Since(start)
		if err == nil {
			log.Infof(green("task %q exec success, use time %q"), r.cmd, useTime)
			if stderr.Len() > 5 {
				log.Infof(green("-----stderr-----\n%s\n-----end stderr-----"), stderr.String())
			}
		} else {
			log.Errorf(red("task %q exec error %v, use time %q"), r.cmd, err, useTime)
			log.Infof(red("-----output-----\n%s\n-----end output-----"), combinedOutput.String())
			os.Exit(1)
		}
	case <-time.After(time.Duration(r.timeout) * time.Millisecond):
		log.Errorf(red("task %q exec error timeout %v"), r.cmd, r.timeout)
		log.Infof(red("-----output-----\n%s\n-----end output-----"), combinedOutput.String())
		os.Exit(1)
	}
}

func main() {
	var timeout = flag.Int("timeout", 120*1000, "timeout ms")
	flag.Parse()
	cmd := flag.Arg(0)
	r := run{timeout: *timeout, cmd: cmd}
	r.exec()
}

var (
	codeByColor = map[string]int{
		"black":   30,
		"red":     31,
		"green":   32,
		"yellow":  33,
		"blue":    34,
		"magenta": 35,
		"cyan":    36,
		"white":   37,
	}

	black       = colorizer("black")
	red         = colorizer("red")
	green       = colorizer("green")
	yellow      = colorizer("yellow")
	blue        = colorizer("blue")
	magenta     = colorizer("magenta")
	cyan        = colorizer("cyan")
	white       = colorizer("white")
	boldBlack   = colorizer("Black")
	boldRed     = colorizer("Red")
	boldGreen   = colorizer("Green")
	boldYellow  = colorizer("Yellow")
	boldBlue    = colorizer("Blue")
	boldMagenta = colorizer("Magenta")
	boldCyan    = colorizer("Cyan")
	boldWhite   = colorizer("White")
)

func colorize(text, color string) string {
	return colorizer(color)(text)
}

func colorizer(color string) func(string) string {
	if code, ok := codeByColor[color]; ok {
		return func(text string) string {
			return fmt.Sprintf("\033[%dm%s\033[0m", code, text)
		}
	} else if code, ok := codeByColor[strings.ToLower(color)]; ok {
		return func(text string) string {
			return fmt.Sprintf("\033[%dm\033[1m%s\033[0m", code, text)
		}
	} else {
		panic("undefined colorizer: " + color)
	}
}
